﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LanguageDetector
{
    /// <summary>
    /// This class is intend to identify the characters in the text and give the language code.
    /// </summary>
    public static class ChracterSetDetector
    {

        //https://en.wikipedia.org/wiki/List_of_Unicode_characters

        // Devanagari. Range: 0900–097F (Hindi)
        // Devanagari Extended. Range: A8E0–A8FF

        //Tamil. Range: 0B80–0BFF

        //Telugu. Range: 0C00–0C7F

        //Kannada. Range: 0C80–0CFF

        //Malayalam. Range: 0D00–0D7F

        //Bengali. Range: 0980–09FF

        //Gujarati. Range: 0A80–0AFF

        //Oriya. Range: 0B00–0B7F

        //Oriya. Range: 0B00–0B7F

        //Sinhala. Range: 0D80–0DFF

        //Punjabi. Range: 0A00-0A7F

        static List<Language> languages;

        static object syncLock = new object();

        static ChracterSetDetector()
        {
            lock (syncLock)
            {
                languages = new List<Language>();

                //simply ascii range...
                languages.Add(new Language { Name = "English", Code = "en", LowerRangePoint = 0, UpperRangePoint = 255 });

                // Devanagari. Range: 0900–097F (Hindi)
                languages.Add(new Language { Name = "Hindi", Code = "hi", LowerRangePoint = int.Parse("0900", System.Globalization.NumberStyles.HexNumber), UpperRangePoint = int.Parse("097F", System.Globalization.NumberStyles.HexNumber) });

                // Devanagari Extended. Range: A8E0–A8FF
                languages.Add(new Language { Name = "Hindi", Code = "hi", LowerRangePoint = int.Parse("A8E0", System.Globalization.NumberStyles.HexNumber), UpperRangePoint = int.Parse("A8FF", System.Globalization.NumberStyles.HexNumber) }); //this is for extended devenagari range.s

                //Kannada. Range: 0C80–0CFF
                languages.Add(new Language { Name = "Kannada", Code = "kn", LowerRangePoint = int.Parse("0C80", System.Globalization.NumberStyles.HexNumber), UpperRangePoint = int.Parse("0CFF", System.Globalization.NumberStyles.HexNumber) });

                //Tamil. Range: 0B80–0BFF
                languages.Add(new Language { Name = "Tamil", Code = "ta", LowerRangePoint = int.Parse("0B80", System.Globalization.NumberStyles.HexNumber), UpperRangePoint = int.Parse("0BFF", System.Globalization.NumberStyles.HexNumber) });

                //Telugu. Range: 0C00–0C7F
                languages.Add(new Language { Name = "Telugu", Code = "te", LowerRangePoint = int.Parse("0C00", System.Globalization.NumberStyles.HexNumber), UpperRangePoint = int.Parse("0C7F", System.Globalization.NumberStyles.HexNumber) });

                //Malayalam. Range: 0D00–0D7F
                languages.Add(new Language { Name = "Malayalam", Code = "ml", LowerRangePoint = int.Parse("0D00", System.Globalization.NumberStyles.HexNumber), UpperRangePoint = int.Parse("0D7F", System.Globalization.NumberStyles.HexNumber) });

                //Gujarati. Range: 0A80–0AFF
                languages.Add(new Language { Name = "Gujarati", Code = "gu", LowerRangePoint = int.Parse("0A80", System.Globalization.NumberStyles.HexNumber), UpperRangePoint = int.Parse("0AFF", System.Globalization.NumberStyles.HexNumber) });

                //Bengali. Range: 0980–09FF
                languages.Add(new Language { Name = "Bengali", Code = "bn", LowerRangePoint = int.Parse("0980", System.Globalization.NumberStyles.HexNumber), UpperRangePoint = int.Parse("09FF", System.Globalization.NumberStyles.HexNumber) });

                //Oriya. Range: 0B00–0B7F
                languages.Add(new Language { Name = "Oriya", Code = "or", LowerRangePoint = int.Parse("0B00", System.Globalization.NumberStyles.HexNumber), UpperRangePoint = int.Parse("0B7F", System.Globalization.NumberStyles.HexNumber) });

                //Sinhala. Range: 0D80–0DFF
                languages.Add(new Language { Name = "Sinhala", Code = "sin", LowerRangePoint = int.Parse("0D80", System.Globalization.NumberStyles.HexNumber), UpperRangePoint = int.Parse("0DFF", System.Globalization.NumberStyles.HexNumber) });

                //Punjabi. Range: 0A00-0A7F
                languages.Add(new Language { Name = "Punjabi", Code = "punjabi", LowerRangePoint = int.Parse("0A00", System.Globalization.NumberStyles.HexNumber), UpperRangePoint = int.Parse("0A7F", System.Globalization.NumberStyles.HexNumber) });

            }
        }

        public static string Detect(string inputString)
        {

            bool isUnknownsFound = false;

            return Detect(inputString,out isUnknownsFound);

        }

        public static string Detect(string inputString,out bool isUnknownLanguageCharactersFound)
        {
            isUnknownLanguageCharactersFound = false;

            lock (syncLock)
            {
                inputString = inputString.Replace(" ", string.Empty);
                int tempCharCode = -1;

                List<string> languagesFound = new List<string>();

                foreach (var c in inputString.ToCharArray())
                {
                    tempCharCode = (int)c;

                    bool isLanguageDetected = false;

                    foreach (var lng in languages)
                    {
                        if (lng.IsFallInRange(tempCharCode))
                        {
                            languagesFound.Add(lng.Name);
                            //todo: record
                            isLanguageDetected = true;
                            break;
                        }
                    }

                    if (isLanguageDetected == false)
                    {
                        //languagesFound.Add("Unknown");

                        isUnknownLanguageCharactersFound = true;
                    }
                }

                if (languagesFound.Count == 0)
                    return null;

                //bool isUnknownCharsFound = false;

                //var unknownLanguagesCount = (from lng in languagesFound
                //                             where lng.ToLower() == "unknown"
                //                             select lng).ToList<string>().Count;

                //if (unknownLanguagesCount > 0)
                //{
                //    isUnknownCharsFound = true;
                //}

                //isUnknownLanguageCharactersFound = isUnknownCharsFound;



                List<LanguageCount> lngCount = languagesFound
                    .GroupBy(i => i)
                     .Select(i => new LanguageCount
                     {
                         Name = i.Key,
                         Count = i.Count()
                     }).ToList();

                if (lngCount.Count == 0)
                    return null;

                var result = (from l in lngCount
                            orderby l.Count descending
                            select l).FirstOrDefault();

                if (result == null)
                    return null;
                else
                    return result.Name;
            }

        }




        class Language
        {
            public string Name { get; set; }
            public string Code { get; set; }
            public int LowerRangePoint { get; set; }
            public int UpperRangePoint { get; set; }

            public bool IsFallInRange(int code)
            {
                if (code <= UpperRangePoint && code >= LowerRangePoint)
                    return true;
                else
                    return false;
            }
        }

        class LanguageCount
        {
            public string Name { get; set; }
            public int Count { get; set; }
        }




    }
}
